#include "stdafx.h"
#include "tahogen_grammar.h"
#pragma once
#include <map>

using namespace std;


enum MarkupTypeEnum;

using namespace boost::spirit;
using namespace phoenix;





//struct Token
//{
//	Token(MarkupTypeEnum type, std::string text_) : markuptype(type), text(text_)
//	{
//#ifdef DEBUG
//		
//#endif
//	}
//	MarkupTypeEnum markuptype;
//	std::string text;
//};





struct directive
{
	directive() {}
	directive(std::string name_) : name(name_) {}
	std::string name;
	std::vector<std::string> attr_names;
	std::vector<std::string> attr_values;
};

struct directive_closure : boost::spirit::closure<directive_closure, directive>
{
	member1 dir;
};


struct parser_exception
{
	parser_exception(std::string message, int nLine, int nColumn) : msg(message), line(nLine), column(nColumn) {}
	std::string msg;
	int line;
	int column;
};
struct error_report_parser 
{
    char const* eol_msg;
    char const* msg;

    error_report_parser(char const* msg_, char const* eol_msg_) : msg(msg_), eol_msg(eol_msg_)
    {
	}

	typedef boost::spirit::nil_t result_t;

    template <typename ScannerT>
    int
    operator()(ScannerT const& scan, result_t& /*result*/) const
    {
		//file_position fpos = scan.first.get_position();
		//
  //      if (scan.at_end()) 
		//{
  //          if (eol_msg) 
		//	{
  //              //cerr << fpos << eol_msg << endl;
  //              throw parser_exception(eol_msg, fpos.line, fpos.column);
  //          }
  //      } 
		//else 
		//{
  //          if (msg) 
		//	{
  //              file_position fpos = scan.first.get_position();
  //               //cerr << fpos << msg << endl;
		//		throw parser_exception(msg, fpos.line, fpos.column);
  //          }
  //      }

        return -1; // Fail.
    }

};
struct push_back_impl
{
    template <typename Container, typename Item>
    struct result
    {
        typedef void type;
    };

    template <typename Container, typename Item>
    void operator()(Container& c, Item const& item) const
    {
        c.push_back(item);
    }
};


class CallbackImpl 
{
public:
	int id;
public:
	typedef std::vector<Token> container_t;
	typedef container_t::iterator iterator_t;
	 void AddToken(Token token)
	{
#ifdef DEBUG
		cout << "CallbackImpl::AddToken (type: " << token.markuptype << "): " << token.text << endl;
#endif
		tokens.push_back(token);
	}
	iterator_t begin()
	{
		return tokens.begin();
	}
	iterator_t end()
	{
		return tokens.end();
	}
private:
	std::vector<Token> tokens;
};

typedef functor_parser<error_report_parser> error_report_p;

// Parser Errors
#ifndef _PARSE_ERRORS
#define _PARSE_ERRORS
static error_report_p error_invalid_character = error_report_parser("Invalid character found", 0);
static error_report_p error_invalid_filename_character = error_report_parser("Invalid filename characters found", 0);
static error_report_p error_filename_too_long = error_report_parser("Filename is too long", 0);
static error_report_p error_comment_expected = error_report_parser("Comment expected", 0);
static error_report_p error_filename_expected = error_report_parser("Filename expected", 0);
static error_report_p error_missing_closing_commenttag = error_report_parser("Missing closing comment tag", "Unexpected end of file while looking for missing comment tag");
static error_report_p error_missing_closing_scripttag = error_report_parser("Missing closing script tag", "Unexpected end of file while looking for missing closing </script> tag");
static error_report_p error_missing_closing_includetag = error_report_parser("Missing closing include tag", "Unexpected end of file while looking for missing include tag");
static error_report_p error_invalid_directive_identifier = error_report_parser("Invalid directive identifier", 0);
static error_report_p error_invalid_attribute_identifier = error_report_parser("Invalid directive attribute identifier", 0);
static error_report_p error_invalid_attribute_value = error_report_parser("Invalid directive attribute value", 0);
static error_report_p error_attribute_value_expected = error_report_parser("Attribute value expected", 0);
#endif





struct add_token_impl
{
    template <typename Callback, typename Token>
    struct result
    {
        typedef void type;
    };

    template <typename Callback, typename Token>
    void operator()(Callback& callback, Token token) const
    {
#ifdef DEBUG
		cout << "Callback #" << callback.id << ": Adding token\n";
#endif
		callback.AddToken(token);
    }
};

struct add_attribute_impl
{
    template <typename Directive, typename AttributeName, typename AttributeValue>
    struct result
    {
        typedef void type;
    };

    template <typename Directive, typename AttributeName, typename AttributeValue>
    void operator()(Directive& d, AttributeName name, AttributeValue val) const
    {
		d.attributes[name] = val;
    }
};

struct add_attributename_impl
{
    template <typename Container, typename Item>
    struct result
    {
        typedef void type;
    };

    template <typename Container, typename Item>
    void operator()(Container& c, Item const& item) const
    {
#ifdef DEBUG
		cout << "add_attributename() called\n";
#endif
        c.attr_names.push_back(item);
    }
};

struct add_attributevalue_impl
{
    template <typename Container, typename Item>
    struct result
    {
        typedef void type;
    };

    template <typename Container, typename Item>
    void operator()(Container& c, Item const& item) const
    {
#ifdef DEBUG
		cout << "add_attributevalue() called\n";
#endif
        c.attr_values.push_back(item);
    }
};
struct set_directive_name_impl
{
    template <typename Container, typename Item>
    struct result
    {
        typedef void type;
    };

    template <typename Container, typename Item>
    void operator()(Container& c, Item const& item) const
    {
		c.name = item;
    }
};
function<push_back_impl> const push_back = push_back_impl();
function<add_token_impl> const add_token = add_token_impl();
function<add_attribute_impl> const add_attribute = add_attribute_impl();
function<add_attributename_impl> const add_attributename = add_attributename_impl();
function<add_attributevalue_impl> const add_attributevalue = add_attributevalue_impl();
function<set_directive_name_impl> const set_directive_name = set_directive_name_impl();

struct parser_closure : boost::spirit::closure<parser_closure, vector<Token> >
{
    member1 tokens;

};
//struct codesmith_grammar : public grammar<codesmith_grammar, parser_closure::context_t>
//{ 
//	
//    template <typename ScannerT> 
//    struct definition 
//    { 
//        definition(codesmith_grammar const& self)
//        { 
//			/* Literal Grammar */
//			literal_char	 = lexeme_d[print_p | space_p | range_p('\253', '\254')] - ("<%" | include_top | open);
//			
//			literal_chars	 = +literal_char;
//			literal_sequence = ((+((literal_char) - ("<%" | include_top) )) )[push_back(self.tokens, construct_<Token>(LiteralText, construct_<std::string>(arg1, arg2)))];
//			literal_top      = literal_sequence;
//
//			/* Directive Grammar */
//			directive_term  = alnum_p - "%>";
//			directive		= ((('@' >> !space_p >> (directive_name) >> +space_p >> *attribute))[push_back(self.tokens, construct_<Token>(Directive, construct_<std::string>(arg1, arg2)))] - "%>") || *space_p;
//			directive_name  = +(directive_term);
//			attribute       = attr_name >> (!space_p >> "=") >> ( (!space_p >> attr_value)) >> *space_p;
//			attr_name       = (+directive_term);
//			attr_value      = confix_p('\"', (+print_p), '\"') | str_p("\"\"");
//			directive_top	= ("<%"  >> (directive) >> "%>") >> *(+space_p >> directive_top);
//			
//			/* Code Grammar */
//			code_sequence = (+(anychar_p - "%>"))[push_back(self.tokens, construct_<Token>(LiteralCode, construct_<std::string>(arg1, arg2)))];
//			code_top	  = "<%" >> ( code_sequence - "%>") >> "%>";
//
//			/* Script Grammar */
//
//			script_term  = ((print_p | punct_p | space_p)  - close);
//			open		 = ch_p('<') >> *space_p >> str_p("script ") >> *space_p >> "runat" >> *space_p >> "=" >> 
//						   *space_p >>"\"template\"" >> *space_p >> ch_p('>');
//
//			content		 = +(script_term);
//
//			close        = ch_p('<') >>  "/script" >> ch_p('>');
//
//			script       = open >> *(content - close)[push_back(self.tokens, construct_<Token>(ScriptBlock, construct_<std::string>(arg1, arg2)))]  >> (close | error_missing_closing_scripttag);
//			script_top   = script;
//			//script_top   = script | (script || +space_p);
//
//			/* Include Grammar */
//			quoted_filename       =  (confix_p('\"', (+include_term)[push_back(self.tokens, construct_<Token>(IncludeFile, construct_<std::string>(arg1, arg2)))], '\"')) | error_filename_expected;
//			include_term		  = (print_p - (ch_p('\\') | '/' | '<' | '>' | '?' | '*')) | error_invalid_filename_character;
//			includetag		      =   ("!--" >> *space_p >> "#" >> *space_p  >> "include " >> ("file" || *space_p) >> ("=" || *space_p) 
//									>> quoted_filename >> *space_p >> ("--" | error_missing_closing_includetag ) );
//			include_top			  = "<" >> (includetag - '>') >>  ">";
//
//			/* Expression Grammar */
//			expression		= ch_p('=') >> *space_p >> (+(print_p - "%>"))[push_back(self.tokens, construct_<Token>(Expression, construct_<std::string>(arg1, arg2)))] >> *space_p;
//			expression_top  = "<%" >> ( expression - "%>") >> "%>";
//
//			/* Comment Grammar */
//
//			comment_term = (print_p | punct_p | space_p) - str_p("--");
//			comment      = (+(comment_term - str_p("--")))[push_back(self.tokens, construct_<Token>(Comment, construct_<std::string>(arg1, arg2)))];
//			commenttag   = ("--" >> *space_p >> comment >> *space_p >> ("--" | error_missing_closing_commenttag ) ) >>  *space_p;
//			comment_top	 = ("<%" >> (commenttag - "%>") >> "%>");
//
//			/* Starting Rule */
//			markup_top       = (script_top | directive_top | comment_top | include_top | expression_top | code_top);
//			top			     = +(markup_top | lexeme_d[literal_top]) >> !top;
//			
//        } 
//
//		typedef rule<ScannerT> rule_t;
//		rule_t     	   literal_char,
//					   literal_chars,
//					   literal_sequence,
//					   directive_term,
//					   directive,
//					   directive_name,
//					   attribute,
//					   attr_name,
//					   attr_value,
//					   code_sequence,
//			           open,
//			           content,
//			           close,
//			           script_term,
//			           script,
//			    	   quoted_filename,
//	     			   include_term,
//					   includetag,
//					   comment_term,
//					   comment,
//					   commenttag,
//					   expression,
//					   markup,
//					   nonmarkup
//					   ;
//					
//					
//		rule_t directive_top,
//			   literal_top,
//			   code_top,
//			   script_top,
//			   include_top,
//			   comment_top,
//			   expression_top,
//			   markup_top,
//			   top;		   
//					
//		rule<ScannerT> const& 
//        start() const 
//		{ 
//			
//			return top; 
//		} 
//    }; 
//	
//};
void parse(char const *str, vector<Token>& v)
{
	//codesmith_grammar g;
	tahogen_grammar g(v);
	char const* filename = "";
	typedef string::iterator iterator_t;
	string text = str;

	parse_info<iterator_t> info;

	directive dir;
	try
	{
		 info = parse(text.begin(), text.end(), g);
		 //cout << dir.name << endl;
	}
	catch(...)
	{
		
	}
	
}

class codesmithparser
{
public:
	static bool parsetext(char const *str, std::vector<Token>& v)
	{
		
		tahogen_grammar g(v);
	
		char const* filename = "";
		typedef string::iterator iterator_t;
		string text = str;

		parse_info<iterator_t> info;

		
		try
		{
			info = parse(text.begin(), text.end(), g);
			//cout << dir.name << endl;
		}
		catch(exception ex)
		{
			cout << ex.what() << endl;
		}
		return info.full;
	}
};


struct directiveparser
{
	string directivename;
	map<string, string> attributes;
	bool parsedirective(char const* str)
	{
		directivename = "";
		attributes.clear();
		rule<> directive,
			   directive_identifier,
			   directive_attribute_value,
			   directive_attribute;
		
		vector<string> attributenames,
					   attributevalues;

		directive                 = ch_p('@') >> (!space_p >> (+(directive_identifier))[var(directivename) = construct_<string>(arg1, arg2)] >> 
									!(+(space_p | directive_attribute)) >> 
									!space_p);
		directive_identifier      = +alnum_p;
		directive_attribute_value = +(print_p - ch_p('\"'));
		directive_attribute       = *space_p >> directive_identifier[push_back(var(attributenames), construct_<std::string>(arg1, arg2))] >> 
							        *space_p >> "=" >> *space_p >> "\"" 
							        >> (directive_attribute_value[push_back(var(attributevalues), construct_<std::string>(arg1, arg2))]  | eps_p[push_back(var(attributevalues), "")])>> "\"" >> *space_p;
		parse_info<> info = parse(str, directive);

		

		bool bResult = info.full;

		if (bResult)
		{
			// start assigning the attributes

			vector<string>::iterator iterNames = attributenames.begin();
			vector<string>::iterator iterValues = attributevalues.begin();
			while (iterNames != attributenames.end())
			{
				
				attributes[*iterNames] = *iterValues;
				++iterNames;
				++iterValues;
			}
		}
		return bResult;
	}
};
